package com.bzkj.document.service.otheroutbound.impl;

import com.alibaba.fastjson2.JSONObject;
import com.bzkj.common.annotation.DataWarehouseScope;
import com.bzkj.common.constant.BillStatusConstant;
import com.bzkj.common.core.domain.AjaxResult;
import com.bzkj.common.core.domain.model.LoginUser;
import com.bzkj.common.core.page.TableDataInfo;
import com.bzkj.common.domain.NccApiResponse;
import com.bzkj.common.domain.NccRequestDTO;
import com.bzkj.common.enums.BusinessType;
import com.bzkj.common.enums.DocumentType;
import com.bzkj.common.utils.DataProcessCommonUtils;
import com.bzkj.common.utils.MessageUtil;
import com.bzkj.common.utils.http.NccHttpUtils;
import com.bzkj.document.domain.DocConfirmDTO;
import com.bzkj.document.domain.otheroutorder.dto.IcGeneraloutB;
import com.bzkj.document.domain.otheroutorder.dto.IcGeneraloutH;
import com.bzkj.document.domain.otheroutorder.dto.IcGeneraloutRequestBody;
import com.bzkj.document.domain.otheroutorder.dto.OtherOutQueryDTO;
import com.bzkj.document.domain.otheroutorder.vo.OtherOutBodyVo;
import com.bzkj.document.domain.otheroutorder.vo.OtherOutHeaderVo;
import com.bzkj.document.enums.InventoryCheck;
import com.bzkj.document.enums.ProcessingType;
import com.bzkj.document.exception.InventoryException;
import com.bzkj.document.mapper.OtherOutboundMapper;
import com.bzkj.document.mapper.WmsWareHouseInventoryMapper;
import com.bzkj.document.service.otheroutbound.OtherOutboundOrderService;
import com.bzkj.document.utils.common.DataProcessUtils;
import com.bzkj.document.utils.common.DocumentNoUtils;
import com.bzkj.document.utils.common.InventoryManagerUtils;
import com.bzkj.document.utils.otheroutbound.OtherOutboundUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author C1309
 */
@Service
public class OtherOutboundOrderServiceImpl implements OtherOutboundOrderService {

    private static final String PK_ORG = "111";
    private static final String QUERY_API_URL = "/nccloud/api/ic/generalout/schemequery";
    private static final String UPDATE_API_URL = "/nccloud/api/ic/generalout/update";
    private static final String SIGN_API_URL = "/nccloud/api/ic/generalout/sign";
    private static final String ADD_API_URL = "/nccloud/api/ic/generalout/save";

    @Resource
    private NccHttpUtils nccHttpUtils;
    @Resource
    private OtherOutboundMapper otherOutboundMapper;
    @Resource
    private MessageUtil messageUtil;
    @Resource
    private OtherOutboundUtils otherOutboundUtils;
    @Resource
    private DocumentNoUtils documentNoUtils;
    @Resource
    private InventoryManagerUtils inventoryManagerUtils;
    @Resource
    private WmsWareHouseInventoryMapper wmsWareHouseInventoryMapper;

    /**
     * 查询其他出库单信息
     *
     * @param nccRequestDTO 包含查询条件的请求对象
     * @return 返回分页的查询结果
     */
    @Override
    public TableDataInfo selectOutboundOrder(NccRequestDTO nccRequestDTO) {
        try {
            nccHttpUtils.setWarehouseId(nccRequestDTO, wmsWareHouseInventoryMapper.selectWarehouseId());
            NccApiResponse nccApiResponse = nccHttpUtils.post(QUERY_API_URL, JSONObject.toJSONString(nccRequestDTO));
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);
            List<Map<String, Object>> dataList = otherOutboundUtils.parsingOtherOutboundOrders(nccApiResponse, ProcessingType.SELECT_NCC_ORDER.ordinal(), true);
//            if (dataList == null || dataList.isEmpty()) {
//                throw new RuntimeException("Oops~ 当前条件下没有找到单据，试试调整查询条件吧！");
//            }
            return DataProcessUtils.startPageInfo(nccRequestDTO.getPageNum(), nccRequestDTO.getPageSize(), dataList);
        } catch (Exception e) {
            String errorMessage = messageUtil.operateExceptionMessage(DocumentType.OTHER_OUTBOUND.getCode(), e, "查询");
            throw new RuntimeException(errorMessage, e);
        }
    }

    /**
     * 确认其他出库单
     *
     * @param docConfirmDTO 包含确认信息的请求对象
     * @return 返回操作结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult confirmOutboundOrder(DocConfirmDTO docConfirmDTO) {
        LoginUser loginUser = docConfirmDTO.getLoginUser();
        String billDate = nccHttpUtils.getBillDate(docConfirmDTO.getBillDate());
        List<String> billCodeList = docConfirmDTO.getvBillCodeList();
        int confirmType = docConfirmDTO.getConfirmType();
        List<String> successList = new ArrayList<>();

        for (String billCode : billCodeList) {
            if (isBillExist(billCode)) {
                continue;
            }
            try {
                // 调用NCC接口获取其他出库单数据
                List<Map<String, Object>> otherOutboundOrders = fetchOtherOutboundOrders(billCode, billDate);
                // 处理其他出库单
                String errorMsg = processOtherOutboundOrders(otherOutboundOrders, loginUser, successList, billCode, confirmType);
                if (errorMsg != null) {
                    String[] split = errorMsg.split("x-x");
                    if (split.length == 2) {
                        if ("1".equals(split[0])) {
                            throw new RuntimeException(split[1]);
                        } else if ("2".equals(split[0])) {
                            return AjaxResult.wmsApiWarning(split[1]);
                        }
                    }
                }
            } catch (Exception e) {
                handleException(e, DocumentType.OTHER_OUTBOUND.getCode(), "确认");
            }
        }
        return AjaxResult.success(messageUtil.operateSuccessMessage(successList, DocumentType.OTHER_OUTBOUND.getCode(), "确认"));
    }

    /**
     * 检查单据是否存在
     *
     * @param billCode 单据编码
     * @return 返回单据是否存在
     */
    private boolean isBillExist(String billCode) {
        return otherOutboundMapper.selectIsExist(billCode) > 0;
    }

    /**
     * 获取其他出库单信息
     *
     * @param billCode 单据编码
     * @param billDate 单据日期
     * @return 返回其他出库单信息列表
     * @throws Exception 如果获取过程中发生错误
     */
    private List<Map<String, Object>> fetchOtherOutboundOrders(String billCode, String billDate) throws Exception {
        String confirmQuery = nccHttpUtils.getConfirmQuery(billDate, billCode);
        NccApiResponse nccApiResponse = nccHttpUtils.post(QUERY_API_URL, confirmQuery);
        // 校验NCC返回的数据
        DataProcessCommonUtils.validateNccResponse(nccApiResponse);
        // 解析NCC返回的数据
        return otherOutboundUtils.parsingOtherOutboundOrders(nccApiResponse, ProcessingType.CONFIRM_ORDER.ordinal(), true);
    }

    /**
     * 处理其他出库单信息
     *
     * @param otherOutboundOrders 其他出库单信息列表
     * @param loginUser           当前登录用户
     * @param successList         成功处理的单据列表
     * @param billCode            单据编码
     * @return 返回错误信息，如果没有错误则返回null
     */
    @Transactional(rollbackFor = Exception.class)
    public String processOtherOutboundOrders(List<Map<String, Object>> otherOutboundOrders, LoginUser loginUser,
                                             List<String> successList, String billCode, int confirmType) {
        try {
            for (Map<String, Object> otherOutboundOrder : otherOutboundOrders) {
                // 提取出库单明细并做进一步处理
                List<Map<String, Object>> detailsList = inventoryManagerUtils.extractDetailsList(otherOutboundOrder, loginUser);
                // 提取出库单头并做进一步处理
                Map<String, Object> headerMap = extractHeaderMap(otherOutboundOrder, loginUser);
                // 检查必填项是否填写
                String errorMsg = inventoryManagerUtils.checkErrorMsg(detailsList);
                if (errorMsg != null) {
                    return "1x-x:" + errorMsg;
                }
                // 校验批次号是否符合先进先出批次号
                String batchNoErrorMsg = inventoryManagerUtils.checkBatchNo(detailsList, confirmType, "warehouseout");
                if (batchNoErrorMsg != null) {
                    return "2x-x:" + batchNoErrorMsg;
                }

                String vtrantypecode = headerMap.get("vtrantypecode").toString();

                // 校验WMS库存并插入明细数据
                int detailsResult = batchInsertDetails(detailsList, vtrantypecode);

                billCode = billCode == null ? (String) headerMap.get("vbillcode") : billCode;

                if (detailsResult == detailsList.size()) {
                    int headerResult = otherOutboundMapper.addOtherOutOrderHeader(headerMap);
                    if (headerResult > 0) {
                        NccApiResponse nccApiResponse = nccHttpUtils.postNoSaleConfirm(UPDATE_API_URL, headerMap.get("cgeneralhid").toString(), "ic_generalout_h", "Y");
                        if (nccApiResponse.isSuccess()) {
                            successList.add(billCode);
                        } else {
                            throw new RuntimeException("向NCC返回单据同步状态失败，请检查后重试！");
                        }
                    }
                }
            }
            return null;
        } catch (Exception e) {
            throw new RuntimeException("单据处理失败：" + e.getMessage(), e);
        }
    }

    /**
     * 提取表头信息并添加必要字段
     *
     * @param otherOutboundOrder 其他出库单信息
     * @param loginUser          当前登录用户
     * @return 返回处理后的表头信息
     */
    private Map<String, Object> extractHeaderMap(Map<String, Object> otherOutboundOrder, LoginUser loginUser) {
        @SuppressWarnings("unchecked")
        Map<String, Object> headerMap = (Map<String, Object>) otherOutboundOrder.get("header");
        String wmsOutNo = documentNoUtils.generateOthOrderNumber();
        headerMap.put("vdef49", wmsOutNo);
        headerMap.put("vdef50", wmsOutNo);
        DataProcessUtils.addHeaderInfo(headerMap, loginUser);
        return headerMap;
    }

    /**
     * 提取明细信息并添加必要字段
     *
     * @param materialOutboundOrder 其他出库单信息
     * @param loginUser             当前登录用户
     * @return 返回处理后的明细信息列表
     */
    private List<Map<String, Object>> extractDetailsList(Map<String, Object> materialOutboundOrder, LoginUser loginUser) {
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> detailsList = (List<Map<String, Object>>) materialOutboundOrder.get("details");
        for (Map<String, Object> detailMap : detailsList) {
            DataProcessUtils.addDetailInfo(detailMap, loginUser);
        }
        return detailsList;
    }

    /**
     * 批量插入明细信息
     *
     * @param detailsList   明细信息列表
     * @param vtrantypecode 交易类型编码
     * @return 返回成功插入的记录数
     */
    private int batchInsertDetails(List<Map<String, Object>> detailsList, String vtrantypecode) {
        AtomicInteger count = new AtomicInteger();
        // 判断库存量是否充足
        boolean verifyInventoryConfirm = inventoryManagerUtils.verifyInventoryConfirm(detailsList, "warehouseout", vtrantypecode, DocumentType.OTHER_OUTBOUND.getCode());
        if (verifyInventoryConfirm) {
            detailsList.forEach(detail -> {
                count.addAndGet(otherOutboundMapper.addOtherOutOrderDetails(detail));
            });
        }
        return count.get();
    }

    /**
     * 处理异常信息
     *
     * @param e            异常对象
     * @param documentType 单据类型
     * @param operation    操作类型
     */
    private void handleException(Exception e, String documentType, String operation) {
        String exceptionMessage = messageUtil.operateExceptionMessage(documentType, e, operation);
        throw new RuntimeException(exceptionMessage, e);
    }

    /**
     * 新增其他出库单
     *
     * @param icGeneraloutRequestBody 包含新增信息的请求对象
     * @return 返回操作结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult addOtherOutboundOrder(IcGeneraloutRequestBody icGeneraloutRequestBody) {
        List<String> successList = new ArrayList<>();
        LoginUser loginUser = icGeneraloutRequestBody.getLoginUser();
        IcGeneraloutH icGeneraloutH = icGeneraloutRequestBody.getIcGeneraloutH();
        List<IcGeneraloutB> icGeneraloutBodyList = icGeneraloutRequestBody.getIcGeneraloutBList();
        if (icGeneraloutH == null) {
            return AjaxResult.warn("小提示：其他出库单据头信息缺失，请确认提交的请求格式是否正确！");
        }
        if (icGeneraloutBodyList == null || icGeneraloutBodyList.isEmpty()) {
            return AjaxResult.warn("注意：未提供任何其他出库单明细信息");
        }

        for (IcGeneraloutB icGeneraloutB : icGeneraloutBodyList) {
            if (icGeneraloutB.getNshouldnum().equals("0")) {
                return AjaxResult.warn("注意：提供的明细数据中应出主数量存在为0项，请核对后重试！");
            }
        }
//        Map<String, Object> map = new HashMap<>();
//        List<Map<String, Object>> detailsList = new ArrayList<>();
        try {
//        for (IcGeneraloutB icGeneraloutB : icGeneraloutBodyList) {
//            Class<?> clazz = icGeneraloutB.getClass();
//            for (Field field : clazz.getDeclaredFields()) {
//                field.setAccessible(true); // 强制访问私有字段
//                map.put(field.getName(), field.get(icGeneraloutB));
//            }
//            detailsList.add(map);
//        }
//        // 校验WMS库存
//        inventoryManagerUtils.verifyInventoryConfirm(detailsList, "warehouseout", icGeneraloutH.getCtrantypeid(), DocumentType.OTHER_OUTBOUND.getCode());
            String otherOutboundRequestBody = JSONObject.toJSONString(icGeneraloutRequestBody);

            NccApiResponse nccApiResponse = nccHttpUtils.post(ADD_API_URL, "[" + otherOutboundRequestBody + "]");
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);
            List<Map<String, Object>> list = otherOutboundUtils.parsingOtherOutboundOrders(nccApiResponse, ProcessingType.CONFIRM_ORDER.ordinal(), true);
            String errorMsg = processOtherOutboundOrders(list, loginUser, successList, null, 1);
            if (errorMsg != null) {
                String[] split = errorMsg.split("x-x");
                if (split.length == 2) {
                    if ("1".equals(split[0])) {
                        throw new RuntimeException(split[1]);
                    } else if ("2".equals(split[0])) {
                        return AjaxResult.wmsApiWarning(split[1]);
                    }
                }
            }
        } catch (Exception e) {
            String exceptionMessage = messageUtil.operateExceptionMessage(DocumentType.OTHER_OUTBOUND.getCode(), e, "新增");
            throw new RuntimeException(exceptionMessage, e);
        }
        return AjaxResult.success(messageUtil.operateSuccessMessage(successList, DocumentType.OTHER_OUTBOUND.getCode(), "新增"));
    }

    /**
     * 获取本地其他出库单信息
     *
     * @param otherOutQueryDTO 包含查询条件的请求对象
     * @param pageNum          当前页码
     * @param pageSize         每页记录数
     * @return 返回分页的查询结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    @DataWarehouseScope(deptAlias = "d", userAlias = "u")
    public TableDataInfo getLocalOtherOutboundOrder(OtherOutQueryDTO otherOutQueryDTO, int pageNum, int pageSize) {
        DataProcessUtils.handleDateRange(otherOutQueryDTO);
        // 处理单据状态过滤条件
        String originalBillsState = Optional.ofNullable(otherOutQueryDTO.getBillsState())
                .filter(state -> !state.isEmpty())
                .orElse(null);

        // For header query, we modify state 4/5 to 3
        String headerQueryBillsState = originalBillsState != null
                ? (originalBillsState.equals("4") || originalBillsState.equals("5") ? "3" : originalBillsState)
                : null;
        otherOutQueryDTO.setBillsState(headerQueryBillsState);

        List<OtherOutHeaderVo> localOtherOutboundOrderList = otherOutboundMapper.getLocalOtherOutboundOrder(otherOutQueryDTO);
        if (localOtherOutboundOrderList == null || localOtherOutboundOrderList.isEmpty()) {
            return DataProcessCommonUtils.getTableInfo(Collections.emptyList(), pageNum, pageSize);
        }
        // 获取物料过滤条件
        String filterMaterialOid = Optional.ofNullable(otherOutQueryDTO.getMaterial()).orElse("");
        boolean shouldFilterByMaterial = !filterMaterialOid.isEmpty();
        boolean shouldFilterBySkuState = originalBillsState != null
                && (originalBillsState.equals("4") || originalBillsState.equals("5"));

        List<HashMap<String, Object>> responseDataList = localOtherOutboundOrderList.parallelStream().map(headerVO -> {
                    // 查询对应单据明细
                    List<OtherOutBodyVo> localOtherOutboundOrderDetails = otherOutboundMapper.getLocalOtherOutboundOrderDetails(
                            headerVO.getCgeneralhid(), headerQueryBillsState);
                    if (localOtherOutboundOrderDetails == null || localOtherOutboundOrderDetails.isEmpty()) {
                        return null;
                    }
                    // 应用过滤条件
                    if (shouldFilterByMaterial && localOtherOutboundOrderDetails.stream()
                            .noneMatch(body -> filterMaterialOid.equals(body.getCmaterialoid().getPk()))) {
                        return null;
                    }
                    if (shouldFilterBySkuState && localOtherOutboundOrderDetails.stream().noneMatch(body -> originalBillsState.equals(body.getSkuState()))) {
                        return null;
                    }
                    // 构建结果
                    HashMap<String, Object> result = new HashMap<>(2);
                    result.put("header", headerVO);
                    result.put("details", localOtherOutboundOrderDetails);
                    return result;
                }).filter(Objects::nonNull)
                .collect(Collectors.toList());
        return DataProcessCommonUtils.getTableInfo(responseDataList, pageNum, pageSize);
    }

    /**
     * 撤销其他出库单
     *
     * @param headerId  表头ID
     * @param loginUser 当前登录用户
     * @return 返回操作结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult orderBack(String headerId, LoginUser loginUser) {
        HashMap<String, String> billStatusMap = otherOutboundMapper.getBillStatus(headerId);
        String billState = billStatusMap.get("billState");
        String vbillCode = billStatusMap.get("vbillcode");
        AjaxResult ajaxResult = messageUtil.cancelExtractBillMessage(billState, DocumentType.OTHER_OUTBOUND.getDescription());
        return ajaxResult.isSuccess() ? processOrderBack(headerId, loginUser, vbillCode) : ajaxResult;
    }

    private AjaxResult processOrderBack(String headerId, LoginUser loginUser, String vbillCode) {
        int i = otherOutboundMapper.orderBackHead(headerId, loginUser.getUserId().toString());
        if (i > 0) {
            int i1 = otherOutboundMapper.orderBackDetails(headerId, loginUser.getUserId().toString());
            if (i1 > 0) {
                return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vbillCode), DocumentType.OTHER_OUTBOUND.getCode(), "取消提取"));
            }
        }
        return AjaxResult.error("系统出现未知错误，请联系系统管理员处理！");
    }

    /**
     * 更新其他出库单
     *
     * @param responseBody 包含更新信息的请求体
     * @param loginUser    当前登录用户
     * @param isSign       是否为签字操作
     * @return 返回操作结果
     */
    @Override
    public AjaxResult updateOtherOutBoundOrder(HashMap<String, Object> responseBody, LoginUser loginUser, boolean isSign) {
        String vbillcode;
        try {
            HashMap<String, Object> headerMap = extractHeaderInfo(responseBody);
            String cgeneralhid = headerMap.get("cgeneralhid").toString();
            if (!isSign) {
                AjaxResult validationResult = validateBillStatus(cgeneralhid);
                if (!validationResult.isSuccess()) {
                    return validationResult;
                }
            }
            HashMap<String, Object> nccRequestMap = prepareNccRequest(responseBody);
            JSONObject jsonObject = new JSONObject(nccRequestMap);
            JSONObject icGeneraloutH = jsonObject.getJSONObject("ic_generalout_h");
            if (icGeneraloutH.get("cwarehouseid") != null){
                icGeneraloutH.remove("cwarehouseid");
            }

            NccApiResponse nccApiResponse = nccHttpUtils.post(UPDATE_API_URL, jsonObject.toJSONString());
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);
            List<Map<String, Object>> list = otherOutboundUtils.parsingOtherOutboundOrders(nccApiResponse, ProcessingType.UPDATE_NCC_ORDER.ordinal(), false);
            vbillcode = processOutboundOrders(list, loginUser);
        } catch (Exception e) {
            String exceptionMessage;
            if (!isSign) {
                exceptionMessage = messageUtil.operateExceptionMessage(DocumentType.OTHER_OUTBOUND.getCode(), e, "修改");
            } else {
                return AjaxResult.error(messageUtil.operateExceptionMessage(DocumentType.OTHER_OUTBOUND.getCode(), e, "签字"));
            }
            throw new RuntimeException(exceptionMessage, e);
        }
        return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vbillcode), DocumentType.OTHER_OUTBOUND.getCode(), "修改"));
    }

    /**
     * 提取表头信息
     *
     * @param responseBody 包含表头信息的请求体
     * @return 返回提取的表头信息
     */
    private HashMap<String, Object> extractHeaderInfo(HashMap<String, Object> responseBody) {
        @SuppressWarnings("unchecked")
        HashMap<String, Object> headerMap = (HashMap<String, Object>) responseBody.get("ic_generalout_h");
        if (headerMap == null || !headerMap.containsKey("cgeneralhid")) {
            throw new IllegalArgumentException("提示：单据头信息缺失或不完整！");
        }
        return headerMap;
    }

    /**
     * 验证单据状态
     *
     * @param cgeneralhid 表头ID
     * @return 返回验证结果
     */
    private AjaxResult validateBillStatus(String cgeneralhid) {
        HashMap<String, String> billInfoMap = otherOutboundMapper.getBillStatus(cgeneralhid);
        String billState = billInfoMap.get("billState");
        return messageUtil.updateBillMessage(billState, DocumentType.OTHER_OUTBOUND.getDescription());
    }

    /**
     * 准备NCC请求数据
     *
     * @param responseBody 包含请求信息的请求体
     * @return 返回处理后的请求数据
     */
    private HashMap<String, Object> prepareNccRequest(HashMap<String, Object> responseBody) {
        HashMap<String, Object> nccRequestMap = new HashMap<>(2);
        nccRequestMap.put("ic_generalout_h", responseBody.get("ic_generalout_h"));
        nccRequestMap.put("ic_generalout_b", responseBody.get("ic_generalout_b"));
        return nccRequestMap;
    }

    /**
     * 处理其他出库单信息
     *
     * @param otherOutboundOrders 其他出库单信息列表
     * @param loginUser           当前登录用户
     * @return 返回处理后的单据编码
     */
    private String processOutboundOrders(List<Map<String, Object>> otherOutboundOrders, LoginUser loginUser) {
        String vbillcode = "";
        for (Map<String, Object> otherOutboundOrder : otherOutboundOrders) {
            @SuppressWarnings("unchecked")
            Map<String, Object> headerInfoMap = (Map<String, Object>) otherOutboundOrder.get("header");
            vbillcode = headerInfoMap.get("vbillcode").toString();
            DataProcessUtils.updateInfo(headerInfoMap, loginUser);
            int resultNum = otherOutboundMapper.updateOtherOutboundOrder(headerInfoMap);
            if (resultNum <= 0) {
                throw new RuntimeException("表头数据更新失败！");
            }
            @SuppressWarnings("unchecked")
            List<HashMap<String, Object>> detailsList = (List<HashMap<String, Object>>) otherOutboundOrder.get("details");
            int count = updateOrderDetails(detailsList, loginUser);
            if (count != detailsList.size()) {
                String failureMessage = messageUtil.documentFailureMessage(Collections.singletonList(headerInfoMap.get("vbillcode").toString()), DocumentType.OTHER_OUTBOUND.getCode(), "修改", "明细");
                throw new RuntimeException(failureMessage);
            }
        }
        return vbillcode;
    }

    /**
     * 更新其他出库单明细信息
     *
     * @param detailsList 明细信息列表
     * @param loginUser   当前登录用户
     * @return 返回成功更新的记录数
     */
    private int updateOrderDetails(List<HashMap<String, Object>> detailsList, LoginUser loginUser) {
        int count = 0;
        for (HashMap<String, Object> detailMap : detailsList) {
            DataProcessUtils.updateInfo(detailMap, loginUser);
            count += otherOutboundMapper.updateOtherOutboundOrderDetails(detailMap);
        }
        return count;
    }

    /**
     * 签字其他出库单
     *
     * @param cgeneralhid 表头ID
     * @param loginUser   当前登录用户
     * @return 返回操作结果
     */
    @Override
    public AjaxResult signatureOutBound(String cgeneralhid, LoginUser loginUser) {
        if (cgeneralhid == null || cgeneralhid.isEmpty()) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.OTHER_OUTBOUND.getCode(), "签字"));
        }
        HashMap<String, String> billStatusMap = otherOutboundMapper.getBillStatus(cgeneralhid);
        String billState = billStatusMap.get("billState");
        String vbillcode = billStatusMap.get("vbillcode");
        AjaxResult ajaxResult = messageUtil.signedBillMessage(billState, DocumentType.OTHER_OUTBOUND.getDescription());
        return ajaxResult.isSuccess() ? processSignBill(cgeneralhid, vbillcode, loginUser) : ajaxResult;
    }

    /**
     * 处理签字其他出库单
     *
     * @param cgeneralhid 表头ID
     * @param loginUser   当前登录用户
     * @param vbillcode   单据编码
     * @return 返回操作结果
     */
    private AjaxResult processSignBill(String cgeneralhid, String vbillcode, LoginUser loginUser) {
        try {
            // 准备表头数据
            HashMap<String, Object> headerMap = prepareHeaderData(cgeneralhid);
            String vtrantypecode = headerMap.get("vtrantypecode").toString();
            // 校验并准备明细数据
            List<HashMap<String, Object>> detailList = prepareDetails(cgeneralhid, vtrantypecode);
            if (detailList.isEmpty()) {
                return AjaxResult.error(messageUtil.updateDocumentZeroQuantityMessage(DocumentType.OTHER_OUTBOUND.getCode()));
            }
            AjaxResult updateResult = updateOtherOutOrder(headerMap, detailList, loginUser);
            if (!updateResult.isSuccess()) {
                return updateResult;
            }
            return handleExternalApiAndInventory(cgeneralhid, vbillcode, loginUser, detailList.size());
        } catch (IOException e) {
            String exceptionMessage = messageUtil.operateExceptionMessage(DocumentType.OTHER_OUTBOUND.getCode(), e, "签字");
            throw new RuntimeException(exceptionMessage, e);
        }
    }

    /**
     * 准备明细信息
     *
     * @param cgeneralhid   表头ID
     * @param vtrantypecode 交易类型编码
     * @return 返回处理后的明细信息列表
     */
    private List<HashMap<String, Object>> prepareDetails(String cgeneralhid, String vtrantypecode) {
        // 查询单据明细数据信息
        List<OtherOutBodyVo> details = otherOutboundMapper.getLocalOtherOutboundOrderDetails(cgeneralhid, null);
        // 构建更新明细表
        List<HashMap<String, Object>> detailList = new ArrayList<>();
        // 判断库存是否充足
        boolean verifyInventory = inventoryManagerUtils.verifyInventorySign(details, "warehouseout", vtrantypecode, DocumentType.OTHER_OUTBOUND.getCode());
        if (verifyInventory) {
            for (OtherOutBodyVo detail : details) {
                HashMap<String, Object> detailMap = new HashMap<>();
                detailMap.put("cgeneralbid", detail.getCgeneralbid());
                detailMap.put("nnum", detail.getNnum());
                detailList.add(detailMap);
            }
        }
        return detailList;
    }

    /**
     * 准备表头信息
     *
     * @param cgeneralhid 表头ID
     * @return 返回处理后的表头信息
     */
    private HashMap<String, Object> prepareHeaderData(String cgeneralhid) {
        OtherOutHeaderVo otherOutHeaderVo = otherOutboundMapper.selectOtherOutboundOrderHeaderByBillCode(cgeneralhid);
        if (otherOutHeaderVo == null) {
            throw new IllegalStateException("其他出库单表头信息不存在！");
        }
        HashMap<String, Object> headerMap = new HashMap<>();
        headerMap.put("cgeneralhid", otherOutHeaderVo.getCgeneralhid());
        headerMap.put("vtrantypecode", otherOutHeaderVo.getVtrantypecode());
        return headerMap;
    }

    /**
     * 更新其他出库单
     *
     * @param headerMap  表头信息
     * @param detailList 明细信息列表
     * @param loginUser  当前登录用户
     * @return 返回操作结果
     */
    private AjaxResult updateOtherOutOrder(HashMap<String, Object> headerMap, List<HashMap<String, Object>> detailList, LoginUser loginUser) {
        HashMap<String, Object> resultMap = new HashMap<>();
        resultMap.put("ic_generalout_h", headerMap);
        resultMap.put("ic_generalout_b", detailList);
        return updateOtherOutBoundOrder(resultMap, loginUser, true);
    }

    /**
     * 处理外部API调用和库存更新
     *
     * @param cgeneralhid 表头ID
     * @param vBillCode   单据编码
     * @param loginUser   当前登录用户
     * @param detailSize  明细数量
     * @return 返回操作结果
     * @throws IOException 如果处理过程中发生IO错误
     */
    private AjaxResult handleExternalApiAndInventory(String cgeneralhid, String vBillCode, LoginUser loginUser, int detailSize) throws IOException {
        NccApiResponse apiResponse = nccHttpUtils.post(SIGN_API_URL, "[" + cgeneralhid + "]");
        DataProcessCommonUtils.validateNccResponse(apiResponse);
        otherOutboundMapper.updateBillState(cgeneralhid, BillStatusConstant.SIGNED_CODE, loginUser.getUsername(), null);
        Integer rowCount = inventoryManagerUtils.wmsWarehouseOut(vBillCode, "OtherWareHouseOut");
        if (rowCount != null && detailSize == rowCount) {
            return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vBillCode), DocumentType.OTHER_OUTBOUND.getCode(), "签字"));
        } else {
            otherOutboundMapper.updateBillState(cgeneralhid, BillStatusConstant.WMS_FAILURE_CODE, loginUser.getUsername(), null);
            return AjaxResult.error(messageUtil.updateDocumentWmsFailureMessage(DocumentType.OTHER_OUTBOUND.getCode()));
        }
    }

    /**
     * 更新库存信息
     *
     * @param cgeneralhid 表头ID
     * @param loginUser   当前登录用户
     * @return 返回操作结果
     */
    @Override
    public AjaxResult updateInventory(String cgeneralhid, LoginUser loginUser) {
        try {
            OtherOutHeaderVo otherOutHeaderVo = otherOutboundMapper.selectOtherOutboundOrderHeaderByBillCode(cgeneralhid);
            List<OtherOutBodyVo> details = otherOutboundMapper.getLocalOtherOutboundOrderDetails(cgeneralhid, null);
//            checkInventory(details, otherOutHeaderVo);
            inventoryManagerUtils.verifyInventorySign(details, "warehouseout", otherOutHeaderVo.getVtrantypecode(), DocumentType.OTHER_OUTBOUND.getCode());
            Integer rowCount = inventoryManagerUtils.wmsWarehouseIn(otherOutHeaderVo.getVbillcode(), "OtherWareHouseOut");
            updateBillState(cgeneralhid, loginUser, rowCount, details.size());
            return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(otherOutHeaderVo.getVbillcode()), DocumentType.OTHER_OUTBOUND.getCode(), "签字"));
        } catch (InventoryException e) {
            return AjaxResult.error(e.getMessage());
        } catch (Exception e) {
            return AjaxResult.error(e.getMessage());
        }
    }

    /**
     * 删除其他出库单
     *
     * @param cgeneralhid 单据表头主键
     * @param loginUser   登录用户
     * @param reason      作废原因
     * @return 操作结果
     */
    @Override
    public AjaxResult deleteOtherOutBoundOrder(String cgeneralhid, LoginUser loginUser, String reason) {
        if (cgeneralhid == null) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.OTHER_OUTBOUND.getCode(), "作废"));
        } else if (cgeneralhid.trim().isEmpty()) {
            return AjaxResult.error(messageUtil.noSelectOrderMessage(DocumentType.OTHER_OUTBOUND.getCode(), "作废"));
        }
        // 获取当前单据状态
        HashMap<String, String> billStateMap = otherOutboundMapper.getBillStatus(cgeneralhid);
        String billStatus = billStateMap.get("billState");
        String vbillcode = billStateMap.get("vbillcode");

        // 调用消息工具（根据不同的单据状态返回不同的消息）
        AjaxResult ajaxResult = messageUtil.deleteBillMessage(billStatus, DocumentType.OTHER_OUTBOUND.getDescription());
        return ajaxResult.isSuccess() ? handleDeleteBill(cgeneralhid, vbillcode, loginUser, reason) : ajaxResult;

    }

    /**
     * 作废材料出库单
     *
     * @param cgeneralhid 表头主键
     * @param vbillcode   单据号
     * @param loginUser   登录用户
     * @param reason      作废原因
     * @return 操作结果
     */
    private AjaxResult handleDeleteBill(String cgeneralhid, String vbillcode, LoginUser loginUser, String reason) {
        try {
            // 调用删除接口
            NccApiResponse nccApiResponse = nccHttpUtils.postNoSaleConfirm(UPDATE_API_URL, cgeneralhid, "ic_generalout_h", "");
            // 校验NCC返回的数据
            DataProcessCommonUtils.validateNccResponse(nccApiResponse);
            otherOutboundMapper.updateBillState(cgeneralhid, BillStatusConstant.DELETED_CODE, loginUser.getUsername(), reason);

            // 校验NCC响应
            return AjaxResult.success(messageUtil.operateSuccessMessage(Collections.singletonList(vbillcode), DocumentType.OTHER_OUTBOUND.getCode(), BusinessType.INVALID.getDescription()));
        } catch (Exception e) {
            String errorMessage = messageUtil.operateExceptionMessage(DocumentType.OTHER_OUTBOUND.getCode(), e, BusinessType.INVALID.getDescription());
            //            log.error("采购入库单修改异常: ", e);
            throw new RuntimeException(errorMessage, e);
        }
    }

    /**
     * 检查库存信息
     *
     * @param details          明细信息列表
     * @param otherOutHeaderVo 表头信息
     * @throws InventoryException 如果库存检查失败
     */
    private void checkInventory(List<OtherOutBodyVo> details, OtherOutHeaderVo otherOutHeaderVo) throws InventoryException {
        for (OtherOutBodyVo detail : details) {
            if (detail.getNshouldnum() > 0) {
                int resultType = inventoryManagerUtils.isEnough(detail.getVbillcode(), otherOutHeaderVo.getVtrantypecode(), detail.getCmaterialvid().getPk(), detail.getVbatchcode(), detail.getNnum(), "2", detail.getCstateid(), "", "");
                if (resultType == InventoryCheck.NO_ENOUGH.ordinal()) {
                    throw new InventoryException(detail.getCmaterialvid().getName() + "库存可用量不足！");
                } else if (resultType == InventoryCheck.NOT_ALLOWED.ordinal()) {
                    throw new InventoryException(detail.getCmaterialvid().getName() + "当前商品不支持在此单据类型下使用！");
                }
            }
        }
    }

    /**
     * 更新单据状态
     *
     * @param cgeneralhid 表头ID
     * @param loginUser   当前登录用户
     * @param rowCount    更新记录数
     * @param detailSize  明细数量
     */
    private void updateBillState(String cgeneralhid, LoginUser loginUser, Integer rowCount, int detailSize) {
        if (rowCount != null && rowCount == detailSize) {
            otherOutboundMapper.updateBillState(cgeneralhid, BillStatusConstant.SIGNED_CODE, loginUser.getUsername(), null);
        } else {
            throw new RuntimeException(messageUtil.updateDocumentWmsFailureMessage(DocumentType.OTHER_OUTBOUND.getCode()));
        }
    }
}